package com.future.auth.controller;

import cn.hutool.core.util.StrUtil;
import com.future.common.api.content.CacheConstants;
import com.future.common.api.content.SecurityConstant;
import com.future.common.api.result.R;
import com.future.common.security.annoation.Ignore;
import com.future.common.security.utils.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.security.oauth2.provider.ClientDetailsService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * @ClassName : AuthController
 * @Author : lby
 * @Date: 2021/5/6 22:18
 * @Description :
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/token")
public class AuthController {
    private static final String smartStatus_OAUTH_ACCESS = SecurityConstant.smartStatus_PREFIX + SecurityConstant.OAUTH_PREFIX + "auth_to_access:";
    private final ClientDetailsService clientDetailsService;
    private final RedisTemplate<String,String> redisTemplate;
    private final TokenStore tokenStore;
    private final CacheManager cacheManager;


    /**
     * 认证页面
     *
     * @param modelAndView
     * @param error        表单登录失败处理回调的错误信息
     * @return ModelAndView
     */
    @GetMapping("/login")
    public ModelAndView require(ModelAndView modelAndView, @RequestParam(required = false) String error) {
        modelAndView.setViewName("ftl/login");
        modelAndView.addObject("error", error);
        return modelAndView;
    }

    /**
     * 确认授权页面
     *
     * @param request
     * @param session
     * @param modelAndView
     * @return
     */
    @GetMapping("/confirm_access")
    public ModelAndView confirm(HttpServletRequest request, HttpSession session, ModelAndView modelAndView) {
        Map<String, Object> scopeList = (Map<String, Object>) request.getAttribute("scopes");
        modelAndView.addObject("scopeList", scopeList.keySet());

        Object auth = session.getAttribute("authorizationRequest");
        if (auth != null) {
            AuthorizationRequest authorizationRequest = (AuthorizationRequest) auth;
            ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
            modelAndView.addObject("app", clientDetails.getAdditionalInformation());
            modelAndView.addObject("user", SecurityUtils.getUser());
        }

        modelAndView.setViewName("ftl/confirm");
        return modelAndView;
    }

    /**
     * 退出token
     *
     * @param authHeader Authorization
     */
    @DeleteMapping("/logout")
    public R logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
        if (StrUtil.isBlank(authHeader) || "undefined".equals(authHeader)) {
            return R.failed("退出失败，token 为空");
        }
        // 退出时清除数据
        if (SecurityUtils.getUser() != null) {
//            R tree = remoteUserService.deleteMenuTree(SecurityUtils.getUser().getId(),SecurityConstant.FROM_IN);
        }
        String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim();
        return delToken(tokenValue);
    }

    /**
     * 令牌管理调用
     *
     * @param token token
     * @return
     */
    @Ignore
    @DeleteMapping("/{token}")
    public R<Boolean> delToken(@PathVariable("token") String token) {
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
        if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
            return R.ok(Boolean.TRUE, "退出失败，token 无效");
        }

        OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
        // 清空用户信息
        cacheManager.getCache(CacheConstants.GLOBALLY + CacheConstants.USER_DETAILS)
                .evict(auth2Authentication.getName());

        // 清空access token
        tokenStore.removeAccessToken(accessToken);

        // 清空 refresh token
        OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
        tokenStore.removeRefreshToken(refreshToken);
        return R.ok();
    }


//    private List<String> findKeysForPage(String patternKey, int pageNum, int pageSize) {
//        ScanOptions options = ScanOptions.scanOptions().count(1000L)
//                .match(patternKey).build();
//        RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
//        Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
//        List<String> result = new ArrayList<>();
//        int tmpIndex = 0;
//        int startIndex = (pageNum - 1) * pageSize;
//        int end = pageNum * pageSize;
//
//        assert cursor != null;
//        while (cursor.hasNext()) {
//            if (tmpIndex >= startIndex && tmpIndex < end) {
//                result.add(cursor.next().toString());
//                tmpIndex++;
//                continue;
//            }
//            if (tmpIndex >= end) {
//                break;
//            }
//            tmpIndex++;
//            cursor.next();
//        }
//
//        cursor.close();
//        return result;
//    }
}
